package com.tbl.modules.wms.controller.outstorage;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.Maps;
import com.tbl.common.utils.*;
import com.tbl.datasources.annotation.NotDuplicate;
import com.tbl.modules.platform.constant.LogActionConstant;
import com.tbl.modules.platform.constant.MenuConstant;
import com.tbl.modules.platform.controller.AbstractController;
import com.tbl.modules.platform.service.system.LogService;
import com.tbl.modules.platform.service.system.RoleService;
import com.tbl.modules.platform.service.system.UserService;
import com.tbl.modules.platform.util.DeriveExcel;
import com.tbl.modules.wms.constant.Constant;
import com.tbl.modules.wms.constant.EmumConstant;
import com.tbl.modules.wms.dao.pda.SplitDAO;
import com.tbl.modules.wms.entity.instorage.InstorageDetail;
import com.tbl.modules.wms.entity.outstorage.OutStorage;
import com.tbl.modules.wms.entity.outstorage.OutStorageDetail;
import com.tbl.modules.wms.entity.split.Split;
import com.tbl.modules.wms.entity.storageinfo.StorageInfo;
import com.tbl.modules.wms.entity.system.Printer;
import com.tbl.modules.wms.service.baseinfo.ShelfService;
import com.tbl.modules.wms.service.instorage.InstorageDetailService;
import com.tbl.modules.wms.service.inventory.InventoryService;
import com.tbl.modules.wms.service.outstorage.OutStorageDetailService;
import com.tbl.modules.wms.service.outstorage.OutStorageService;
import com.tbl.modules.wms.service.pda.SplitService;
import com.tbl.modules.wms.service.storageinfo.StorageInfoService;
import com.tbl.modules.wms.service.system.PrinterService;
import com.tbl.modules.wms.service.webservice.client.WmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 出库管理：发货单管理
 * @author 70486
 */
@Controller
@RequestMapping("/outsrorageCon")
public class OutStorageController extends AbstractController {

    /**
     * 日志信息
     */
    @Autowired
    private LogService logService;
    /**
     * 出库信息主表
     */
    @Autowired
    private OutStorageService outStorageService;
    /**
     * 用户
     */
    @Autowired
    private UserService userService;
    /**
     * 出库信息详情
     */
    @Autowired
    private OutStorageDetailService outStorageDetailService;
    /**
     * 入库信息详情
     */
    @Autowired
    private InstorageDetailService instorageDetailService;
    /**
     * 角色
     */
    @Autowired
    private RoleService roleService;
    /**
     * 盘点计划服务类
     */
    @Autowired
    private InventoryService inventoryService;
    /**
     * 库存查询
     */
    @Autowired
    private StorageInfoService storageInfoService;
    /**
     * 库位
     */
    @Autowired
    private ShelfService shelfService;
    /**
     * 拆分信息
     */
    @Autowired
    private SplitService splitService;
    /**
     * wms接口客户端调用
     */
    @Autowired
    private WmsService wmsService;
    /**
     * 拆分
     */
    @Autowired
    private SplitDAO splitDAO;
    /**
     * 打印配置服务
     */
    @Autowired
    private PrinterService printerService;

    /**
     * 跳转到发货单管理页面
     * @return ModelAndView
     */
    @RequestMapping("/storageList")
    public ModelAndView storageList() {
        ModelAndView mv = this.getModelAndView();
        //okk
        mv.addObject("factoryList",
                inventoryService.getFactoryList(Arrays.asList(getSessionUser().getFactoryCode().split(","))));
        mv.addObject("operationCode",
                roleService.selectOperationByRoleId(getSessionUser().getRoleId(), MenuConstant.outsrorageCon));
        mv.setViewName("techbloom/outstorage/outstorage/outstorage_list");
        return mv;
    }

    /**
     * 拣货下架管理列表页数据
     * @param queryJsonString 查询条件
     * @return Map<String, Object>
     */
    @RequestMapping(value = "/outDanListData.do")
    @ResponseBody
    public Map<String, Object> outDanListData(String queryJsonString) {
        Map<String, Object> map = new HashMap<>(4);
        if (!StringUtils.isEmptyString(queryJsonString)) {
            map = JSON.parseObject(queryJsonString);
        }

        //okk
        map.put("org", Arrays.asList(getSessionUser().getFactoryCode().split(",")));
        PageTbl page = this.getPage();
        PageUtils utils = outStorageDetailService.getDetailPageList(page, map);
        page.setTotalRows(utils.getTotalCount() == 0 ? 1 : utils.getTotalCount());
        //初始化分页对象
        executePageMap(map, page);
        map.put("rows", utils.getList());
        map.put("total", utils.getTotalPage() == 0 ? 1 : utils.getTotalPage());
        return map;
    }

    /**
     * 发货单管理列表页数据
     * @param queryJsonString 查询条件
     * @return Map<String, Object>
     */
    @RequestMapping(value = "/storageListData.do")
    @ResponseBody
    public Map<String, Object> storageListData(String queryJsonString) {
        Map<String, Object> map = new HashMap<>(4);
        if (!StringUtils.isEmptyString(queryJsonString)) {
            map = JSON.parseObject(queryJsonString);
        }
        //okk
        map.put("org", Arrays.asList(getSessionUser().getFactoryCode().split(",")));
        PageTbl page = this.getPage();
        PageUtils utils = outStorageService.getPageList(page, map);
        page.setTotalRows(utils.getTotalCount() == 0 ? 1 : utils.getTotalCount());
        //初始化分页对象
        executePageMap(map, page);
        map.put("rows", utils.getList());
        map.put("total", utils.getTotalPage() == 0 ? 1 : utils.getTotalPage());
        return map;
    }

    /**
     * 点击执行跳转到出库执行界面
     * @param id 出库单主键
     * @return ModelAndView
     */
    @RequestMapping(value = "/execute.do")
    @ResponseBody
    public ModelAndView execute(Integer id) {
        ModelAndView mv = this.getModelAndView();
        mv.addObject("id", id);
        mv.setViewName("techbloom/outstorage/outstorage/outstorage_execute");
        return mv;
    }

    /**
     * 查看出库单明细列表
     * @param id 出库单主键
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/detailList.do")
    @ResponseBody
    public Map<String, Object> detailList(Integer id) {
        Map<String, Object> map = new HashMap<>(2);
        PageTbl page = this.getPage();
        PageUtils utils = outStorageService.getDetailList(page, id);
        page.setTotalRows(utils.getTotalCount() == 0 ? 1 : utils.getTotalCount());
        //初始化分页对象
        executePageMap(map, page);
        map.put("rows", utils.getList());
        map.put("total", utils.getTotalPage() == 0 ? 1 : utils.getTotalPage());
        return map;
    }

    /**
     * 点击查看，跳转到列表页
     * @param id 出库单主键
     * @return ModelAndView
     */
    @RequestMapping(value = "/toInfo.do")
    @ResponseBody
    public ModelAndView toInfo(Long id) {
        ModelAndView mv = this.getModelAndView();
        mv.addObject("infoId", id);
        mv.setViewName("techbloom/outstorage/outstorage/outstorage_info");
        return mv;
    }

    /**
     * 点击编辑，跳转到编辑页面
     * @param id 出库单主键
     * @return ModelAndView
     */
    @RequestMapping(value = "/editInfo.do")
    @ResponseBody
    public ModelAndView editInfo(Long id) {
        ModelAndView mv = this.getModelAndView();
        mv.addObject("info", outStorageService.selectById(id));
        mv.setViewName("techbloom/outstorage/outstorage/outstorage_edit");
        return mv;
    }

    /**
     * 点击编辑，点击保存  保存主表信息
     * @param outStorage 出库单
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/saveOutStorage")
    @ResponseBody
    public Map<String, Object> saveOutStorage(OutStorage outStorage) {
        Map<String, Object> map = new HashMap<>(2);
        boolean result = outStorageService.updateById(outStorage);
        map.put("result", result);
        map.put("msg", result?"保存成功！":"保存失败！");
        return map;
    }

    /**
     * 点击编辑，点击提交，修改状态
     * @param outStorage 出库单
     * @return Mao<String,Object>
     */
    @RequestMapping(value = "/subOutStorage")
    @ResponseBody
    public Map<String, Object> subOutStorage(OutStorage outStorage) {
        Map<String, Object> map = Maps.newHashMap();
        outStorage.setState(Constant.INT_TWO);
        boolean result = outStorageService.updateById(outStorage);
        map.put("result", result);
        map.put("msg", result?"提交成功！":"提交失败！");
        return map;
    }

    /**
     * 点击编辑，获取质保单号列表
     * @param queryString 模糊查询条件
     * @param pageSize 每页数量
     * @param pageNo 页码
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/getQaCode")
    @ResponseBody
    public Map<String, Object> getQaCode(String queryString, int pageSize, int pageNo) {
        Map<String, Object> map = Maps.newHashMap();
        map.put("queryString", StringUtils.isNotEmpty(queryString)?queryString.toUpperCase():"");
        PageTbl page = this.getPage();
        page.setPagesize(pageSize);
        page.setPageno(pageNo);
        PageUtils utils = outStorageService.getQaCode(page, map);
        map.put("total", utils.getTotalCount() == 0 ? 1 : utils.getTotalCount());
        map.put("result", utils.getList() == null ? "" : utils.getList());
        return map;
    }

    /**
     * 点击编辑，发货单详情添加
     * @param id 发货单主键
     * @param qaCodeIds 标签初始化主键
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/saveOutstorageDetail")
    @ResponseBody
    public Map<String, Object> saveOutstorageDetail(Long id, String[] qaCodeIds) {
        Map<String, Object> map = Maps.newHashMap();
        boolean result = outStorageService.saveOutstorageDetail(id, qaCodeIds);
        map.put("result", result);
        map.put("msg", result ? "添加成功！" : "添加失败！");
        return map;
    }

    /**
     * 点击编辑，删除详情数据
     * @param ids 出库详情主键
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/delOutstorageDetail")
    @ResponseBody
    public Map<String, Object> delOutstorageDetail(String[] ids) {
        return outStorageService.deleteOutStorageDetailIds(ids);
    }

    /**
     * 点击出库执行，点击绑定行车  跳转行车绑定页面
     * @param detailId 出库明细主键
     * @param infoId 发货单主键
     * @return ModelAndView
     */
    @RequestMapping(value = "/carbind.do")
    @ResponseBody
    public ModelAndView carbind(Long detailId, Long infoId) {
        OutStorageDetail outStorageDetail = outStorageDetailService.selectById(detailId);
        if(storageInfoService.selectCount(new EntityWrapper<StorageInfo>().eq("QACODE", outStorageDetail.getQaCode()))==0) {
            return null;
        }
        ModelAndView mv = this.getModelAndView();
        mv.setViewName("techbloom/outstorage/outstorage/car_bind");

        List<InstorageDetail> lstInstorageDetail = instorageDetailService.selectByMap(new HashMap<String, Object>(1){{
            put("QACODE", outStorageDetail.getQaCode());
        }});

        mv.addObject("detail", outStorageDetail);
        mv.addObject("carList", lstInstorageDetail.size()>0 ?
                outStorageService.selectCarListByWarehouseCode(lstInstorageDetail.get(0).getWarehouseCode(),
                //okk
                Arrays.asList(getSessionUser().getFactoryCode().split(","))) : new ArrayList<>());
        mv.addObject("infoId", infoId);
        return mv;
    }

    /**
     * 点击出库执行，点击绑定行车  点击保存行车信息
     * @param outStorageDetail 出库详情
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/saveCar")
    @ResponseBody
    public Map<String, Object> saveCar(OutStorageDetail outStorageDetail) {
        Map<String, Object> map = Maps.newHashMap();
        boolean result = outStorageService.saveCar(outStorageDetail);
        map.put("result", result);
        map.put("msg", result?"行车绑定成功！":"行车绑定失败！");
        return map;
    }

    /**
     * 点击出库执行，点击开始拣货
     * @param id 出库单详情主键
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/detailStart")
    @ResponseBody
    public Map<String, Object> detailStart(Long id) {
        Map<String, Object> map = Maps.newHashMap();
        String msg;
        map.put("result", false);
        OutStorageDetail outStorageDetail = outStorageDetailService.selectById(id);
        if (outStorageDetail.getCarCode() == null) {
            msg = "请先选择行车";
            map.put("msg", msg);
            return map;
        }
        if (EmumConstant.outstorageDetailState.OUTSTORAGING.getCode().equals(outStorageDetail.getState())) {
            msg = "请勿重新提交";
            map.put("msg", msg);
            return map;
        }
        if (EmumConstant.outstorageDetailState.OUTSTORAGED.getCode().equals(outStorageDetail.getState())) {
            msg = "拣货完成，请勿重新提交";
            map.put("msg", msg);
            return map;
        }
        if (EmumConstant.outstorageDetailState.OUTSTORAGE_PREPARE.getCode().equals(outStorageDetail.getState())) {
            msg = "发运完成，请勿重新提交";
            map.put("msg", msg);
            return map;
        }
        map.put("result", outStorageService.detailStart(id, getUserId()));
        map.put("msg", "更新成功");
        return map;
    }

    /**
     * 点击出库执行-拣货完成  
     * 弹窗选择全部出还是按米出
     * @param id 出库详情主键
     * @return ModelAndView
     */
    @RequestMapping(value = "/toUpdateMeter.do")
    @ResponseBody
    public ModelAndView toUpdateMeter(Long id) {
        ModelAndView mv = this.getModelAndView();
        mv.addObject("info",outStorageDetailService.selectById(id));
        mv.setViewName("techbloom/outstorage/outstorage/updatemeter");
        return mv;
    }

    /**
     * 单条确认出库，出库完成
     * @param id 出库单明细主键
     * @param outtime 出库时间
     * @param isPrint 是否打印出库单：
     *                1纯出库
     *                2纯打印
     *                3即出库又打印
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/detailSuccess")
    @ResponseBody
    @NotDuplicate
    public Map<String, Object> detailSuccess(Long id, String outtime, Integer isPrint) {
        Integer state = outStorageDetailService.selectById(id).getState();
        if (EmumConstant.outstorageDetailState.OUTSTORAGED.getCode().equals(state)) {
            return new HashMap<String,Object>(2){{
                put("result", false);
                put("msg", "出库完成，请勿重新提交");
            }};
        }else if (EmumConstant.pickingDismount.YES.getCode().equals(YamlConfigurerUtil.getStrYmlVal("yddl.pickingDismount")) &&
                (EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode().equals(state) ||
                        EmumConstant.outstorageDetailState.OUTSTORAGING.getCode().equals(state))){
            //有未下架的
            return new HashMap<String, Object>(2){{
                put("result", false);
                put("msg","必须先拣货下架，才能出库！");
            }};
        }
        return outStorageService.detailSuccess(id, getUserId(), outtime, isPrint);
    }

    /**
     * 获取人员出库量图表
     * @return Map<String,Object>
     */
    @RequestMapping(value = "getPersonOutnum")
    @ResponseBody
    public Map<String, Object> getPersonOutnum() {
        Map<String, Object> map = new HashMap<>(2);
        List<String> nameList = new ArrayList<>();
        List<String> outDataList = new ArrayList<>();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date zero = calendar.getTime();

        //正常出库单、移库出库单、调拨出库
        List<OutStorageDetail> lstOutStorageDetail = outStorageDetailService.findList(zero);
        if (lstOutStorageDetail!=null){
            lstOutStorageDetail.forEach(outStorageDetail -> {
                nameList.add(outStorageDetail.getStartstorageName() == null ? "" : outStorageDetail.getStartstorageName());
                outDataList.add(outStorageDetail.getMeterNumber() == null ? "0" : outStorageDetail.getMeterNumber().toString());
            });
        }

        map.put("nameList", nameList);
        map.put("outDataList", outDataList);
        return map;
    }

    /**
     * 获取人员入库量图表
     * @return Map<String,Object>
     */
    @RequestMapping(value = "getPersonInnum")
    @ResponseBody
    public Map<String, Object> getPersonInnum() {
        Map<String, Object> map = new HashMap<>(2);
        List<String> nameList = new ArrayList<>();
        List<String> inDataList = new ArrayList<>();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date zero = calendar.getTime();

        //正常入库单、移库入库单、调拨出库
        List<InstorageDetail> lstInstorageDetail = instorageDetailService.findList(zero);
        if (lstInstorageDetail!=null){
            lstInstorageDetail.forEach(instorageDetail -> {
                nameList.add(instorageDetail.getInStorageId()!=null?userService.selectById(instorageDetail.getInStorageId()).getName():"");
                inDataList.add(instorageDetail.getMeter() == null ? "0" : instorageDetail.getMeter());
            });
        }

        map.put("nameList", nameList);
        map.put("inDataList", inDataList);
        return map;
    }

    /**
     * 打印出库单页面跳转
     * @return ModelAndView
     */
    @RequestMapping("/print")
    public ModelAndView print() {
        ModelAndView mv = this.getModelAndView();
        mv.addObject("operationCode", roleService.selectOperationByRoleId(getSessionUser().getRoleId(), MenuConstant.print));
        mv.setViewName("techbloom/outstorage/outstorage/print");
        return mv;
    }

    /**
     * 打印出库单-打印
     * @param id 出库明细表主键
     * @return Map<String,Object>
     */
    @RequestMapping("/confirmPrint")
    @ResponseBody
    public Map<String,Object> confirmPrint(Long id) {
        //从打印发货单数据库中获取即将需要被打印得数据列表
        /*returnMap.put("printInfo",outStorageService.getPrintInfo(wayno,outno,type));*/
        return new HashMap<>(1);
}

    /**
     * 点击打印出库单中得查询按钮，返回列表信息
     * @param queryJsonString 查询条件
     * @return Map<String,Object>
     */
    @RequestMapping("/printDataList")
    @ResponseBody
    public Map<String,Object> printDataList(String queryJsonString){
        Map<String, Object> map = new HashMap<>(3);
        if (StringUtils.isNotBlank(queryJsonString)) {
            map = JSON.parseObject(queryJsonString);
        }
        PageTbl page = this.getPage();
        PageUtils utils = outStorageService.getPrintPageList(page, map);
        page.setTotalRows(utils.getTotalCount() == 0 ? 1 : utils.getTotalCount());
        //初始化分页对象
        executePageMap(map, page);
        map.put("rows", utils.getList());
        map.put("total", utils.getTotalPage() == 0 ? 1 : utils.getTotalPage());
        return map;
    }

    /**
     * 导出Excel
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     */
    @RequestMapping(value = "/materialExcel", method = RequestMethod.POST)
    @ResponseBody
    public void materialExcel(HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> map = new HashMap<>();
        map.put("ids", StringUtils.stringToInt(request.getParameter("ids")));
        //okk
        map.put("org", Arrays.asList(getSessionUser().getFactoryCode().split(",")));
        map.put("shipNo", request.getParameter("shipNo"));
        map.put("createTime", request.getParameter("createTime"));
        map.put("endTime", request.getParameter("endTime"));
        map.put("factoryarea",request.getParameter("factoryarea"));
        map.put("orderno", request.getParameter("orderno"));
        map.put("orderline", request.getParameter("orderline"));
        map.put("contractno", request.getParameter("contractno"));

        try {
            String sheetName = "发货单" + "(" + DateUtils.getDay() + ")";
            response.setHeader("Content-Type", "application/force-download");
            response.setHeader("Content-Type", "application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Expires", "0");
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
            response.setHeader("Pragma", "public");
            response.setHeader("Content-disposition", "attachment;filename=" + new String(sheetName.getBytes("gbk"),
                    "ISO8859-1") + ".xls");

            Map<String, String> mapFields = new LinkedHashMap<>();
            String [] excelIndexArray = request.getParameter("queryExportExcelIndex").split(",");

            if (excelIndexArray.length==1&&"".equals(excelIndexArray[0])) {
                mapFields.put("storageState", "发货单状态");
                mapFields.put("name", "发货组织");
                mapFields.put("shipNo", "发货单号");
                mapFields.put("printTime", "打印时间");
                mapFields.put("contractNo", "合同号");
                mapFields.put("orderNo", "订单号");
                mapFields.put("orderLine", "订单行号");
                mapFields.put("transportName", "运输公司");
                mapFields.put("customer", "收获单位");
                mapFields.put("salesName", "销售经理");

            }else {
                for (String s : excelIndexArray) {
                    if ("2".equals(s)) {
                        mapFields.put("storageState", "发货单状态");
                    } else if ("3".equals(s)) {
                        mapFields.put("name", "发货组织");
                    } else if ("4".equals(s)) {
                        mapFields.put("shipNo", "发货单号");
                    } else if ("5".equals(s)) {
                        mapFields.put("printTime", "打印时间");
                    } else if ("6".equals(s)) {
                        mapFields.put("contractNo", "合同号");
                    } else if ("7".equals(s)) {
                        mapFields.put("orderNo", "订单号");
                    } else if ("8".equals(s)) {
                        mapFields.put("orderLine", "订单行号");
                    } else if ("9".equals(s)) {
                        mapFields.put("transportName", "运输公司");
                    } else if ("10".equals(s)) {
                        mapFields.put("customer", "收获单位");
                    } else if ("11".equals(s)) {
                        mapFields.put("salesName", "销售经理");
                    }
                }
            }

            DeriveExcel.exportExcel(sheetName, outStorageService.getExcelList(map), mapFields, response, "");
            logService.logInsert("发货单导出", LogActionConstant.USER_EXPORT, request);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 导出查看列表明细Excel
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     */
    @RequestMapping(value = "/detailExcel.do", method = RequestMethod.POST)
    @ResponseBody
    public void detailExcel(HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> map = new HashMap<>(2);
        //得到要导出的ids
        map.put("ids", StringUtils.stringToInt(request.getParameter("ids")));
        map.put("id", request.getParameter("infoid"));

        try {
            String sheetName = "发货单明细" + "(" + DateUtils.getDay() + ")";
            response.setHeader("Content-Type", "application/force-download");
            response.setHeader("Content-Type", "application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Expires", "0");
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
            response.setHeader("Pragma", "public");
            response.setHeader("Content-disposition", "attachment;filename=" + new String(sheetName.getBytes("gbk"),
                    "ISO8859-1") + ".xls");

            Map<String, String> mapFields = new LinkedHashMap<>();

            mapFields.put("stateStr", "状态");
            mapFields.put("qaCode", "质保号");
            mapFields.put("batchNo", "批次号");
            mapFields.put("dishcode", "盘号");
            mapFields.put("meter", "数量");
            mapFields.put("unit", "单位");
            mapFields.put("model", "盘规格");
            mapFields.put("colour", "颜色");
            mapFields.put("weight", "重量");
            mapFields.put("segmentno", "段号");

            mapFields.put("outstorageOrg", "发货组织");
            mapFields.put("shipNo", "发货单号");
            mapFields.put("printtime", "打印时间");
            mapFields.put("contractno", "合同号");
            mapFields.put("orderno", "订单号");
            mapFields.put("orderline", "订单行号");
            mapFields.put("transportname", "运输公司");
            mapFields.put("customer", "收货单位");
            mapFields.put("salesname", "销售经理");

            DeriveExcel.exportExcel(sheetName, outStorageService.getDetailExcelList(map), mapFields, response, "");
            logService.logInsert("发货单导出", LogActionConstant.USER_EXPORT, request);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 点击确认出库，把所有选中的货物批量出库
     * @param ids 出库单明细主键数组
     * @param outtime 出库时间
     * @param isPrint 是否需要打印：3是；1否
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/outStorageOut")
    @ResponseBody
    @NotDuplicate
    public Map<String, Object> outStorageOut(String[] ids, String outtime, Integer isPrint) {
        List<Long> lstIds = Arrays.stream(ids).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        //已完成的出库单明细主键
        List<Long> lstRemove = new LinkedList<>();
        //未下架的出库单明细主键
        List<Long> lstNoDismount = new LinkedList<>();
        outStorageDetailService.selectBatchIds(lstIds).forEach(outStorageDetail -> {
            if (EmumConstant.outstorageDetailState.OUTSTORAGED.getCode().equals(outStorageDetail.getState())) {
                lstRemove.add(outStorageDetail.getId());
            }
            if (EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode().equals(outStorageDetail.getState()) ||
            EmumConstant.outstorageDetailState.OUTSTORAGING.getCode().equals(outStorageDetail.getState())){
                lstNoDismount.add(outStorageDetail.getId());
            }
        });
        //有未下架的
        if (EmumConstant.pickingDismount.YES.getCode().equals(YamlConfigurerUtil.getStrYmlVal("yddl.pickingDismount")) &&
                lstNoDismount.size()>0){
            return new HashMap<String, Object>(2){{
                put("result", false);
                put("msg","必须先拣货下架，才能出库！");
            }};
        }
        //去掉已经完成出库的明细
        if (lstRemove.size()>0){
            lstIds.removeAll(lstRemove);
        }
        return outStorageService.outsStorageOut(lstIds, getUserId(), outtime, isPrint);
    }

    /**
     * 拣货下架确认下架（等同于手持机出库扫码-预出库）
     * @param ids 出库单明细主键数组
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/preConfirmOut")
    @ResponseBody
    public Map<String, Object> preConfirmOut(String[] ids) {
        //wms发货单明细主键
        List<Long> lstIds = Arrays.stream(ids).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        //查找符合下架条件的
        List<OutStorageDetail> lstOutStorageDetail = outStorageDetailService.getOutStorageDetailAndShipNoListByOutstorageDetailId(lstIds);
        if(lstOutStorageDetail == null || lstOutStorageDetail.size() == 0){
            return new HashMap<String, Object>(2){{
                put("msg", "没有符合下架条件的库存！");
                put("result", false);
            }};
        }

        lstOutStorageDetail.forEach(outStorageDetail -> {
            //预出库时间
            outStorageDetail.setStartStorageTime(new Date());
            //预出库人（下架人）
            outStorageDetail.setStartstorageid(getUserId());
            //状态设为预出库
            outStorageDetail.setState(EmumConstant.outstorageDetailState.OUTSTORAGE_PREPARE.getCode());
            //更新出库明细表
            outStorageDetailService.updateById(outStorageDetail);

            List<Split> lstSplit = splitDAO.selectList(new EntityWrapper<Split>().eq("BATCH_NO", outStorageDetail.getBatchNo()));
            if (lstSplit.size()>0){
                lstSplit.forEach(split -> {
                    split.setState(EmumConstant.storageInfoState.PREOUT.getCode());
                    splitDAO.updateById(split);
                    shelfService.setShelfState(split.getShelfCode(), split.getOrg(), split.getWarehouseCode(),
                            EmumConstant.sheflState.AVAILABLE.getCode());
                });
            }else {
                //更新库存状态
                List<StorageInfo> lstStorageInfo = storageInfoService.selectList(new EntityWrapper<StorageInfo>()
                        .eq("QACODE",outStorageDetail.getQaCode()));
                if(lstStorageInfo.size()>0){
                    StorageInfo storageInfo = lstStorageInfo.get(0);
                    storageInfo.setState(EmumConstant.storageInfoState.PREOUT.getCode());
                    storageInfoService.updateById(storageInfo);
                    //没有拆分的盘，必须整盘出才能释放库位，否则就是因为没在wms做拆分，所以库位还不能释放
                    if (Float.parseFloat(storageInfo.getMeter())-Float.parseFloat(outStorageDetail.getMeter())==0){
                        shelfService.setShelfState(storageInfo.getShelfCode(),storageInfo.getOrg(),storageInfo.getWarehouseCode(),
                                EmumConstant.sheflState.AVAILABLE.getCode());
                    }
                }
            }
        });

        return new HashMap<String, Object>(2){{
            put("msg", "下架成功！");
            put("result", true);
        }};
    }

    /**
     * 拣货下架撤销下架（预出库的库存回退为正常未出库==划单）
     * @param ids 出库单明细主键数组
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/preCancelOut")
    @ResponseBody
    public Map<String, Object> preCancelOut(String[] ids) {
        //wms发货单明细主键
        List<Long> lstIds = Arrays.stream(ids).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        //批量更新发货明细状态
        outStorageDetailService.updateDetailBatches(lstIds, Long.valueOf(EmumConstant.outstorageDetailState.UNOUTSTORAGE.getCode()));
        //更新库存
        outStorageDetailService.selectBatchIds(lstIds).forEach(outStorageDetail -> {
            List<Split> lstSplit = splitService.selectList(new EntityWrapper<Split>().eq("BATCH_NO",outStorageDetail.getBatchNo()));
            if (lstSplit.size()>0){
                lstSplit.forEach(split -> {
                    //状态设为正常
                    split.setState(EmumConstant.storageInfoState.NORMAL.getCode());
                    splitService.updateById(split);
                    shelfService.setShelfState(split.getShelfCode(),split.getOrg(),split.getWarehouseCode(),
                            EmumConstant.sheflState.OCCUPY.getCode());
                });
            }else {
                List<StorageInfo> storageInfoList = storageInfoService.selectList(new EntityWrapper<StorageInfo>()
                        .eq("QACODE",outStorageDetail.getQaCode()));
                if (storageInfoList.size()>0){
                    StorageInfo storageInfo = storageInfoList.get(0);
                    storageInfo.setState(EmumConstant.storageInfoState.NORMAL.getCode());
                    storageInfoService.updateById(storageInfo);
                    shelfService.setShelfState(storageInfo.getShelfCode(),storageInfo.getOrg(),storageInfo.getWarehouseCode(),
                            EmumConstant.sheflState.OCCUPY.getCode());
                }
            }
        });
        return new HashMap<String, Object>(2){{
            put("msg", "撤销成功");
            put("result", true);
        }};
    }

    /**
     * 打印（补打）
     * @param id 提货单主键
     * @return Map<String,Object>
     */
    @RequestMapping(value = "/buprint")
    @ResponseBody
    public Map<String, Object> buprint(Long id) {
        Map<String, Object> resultMap = Maps.newHashMap();
        OutStorage outStorage = outStorageService.selectById(id);
        List<OutStorageDetail> lstOutStorageDetail = outStorageDetailService.selectByMap(new HashMap<String, Object>(1){{
            put("P_ID", id);
        }});

        //判断打印机配置是否已经配置完成
        Printer printer = printerService.findPrinterCodeByUserId(getUserId());
        if (printer == null){
            resultMap.put("result", false);
            resultMap.put("msg", "打印机配置项错误，请联系管理员查看！");
            return resultMap;
        }

        Map<String, Object> batch = Maps.newIdentityHashMap();
        Map<String, Object> qdgroup;
        StringBuilder qacodeBuilder = new StringBuilder(), batchnoBuffer = new StringBuilder();
        if (lstOutStorageDetail.size()>0) {
            for (OutStorageDetail outStorageDetail : lstOutStorageDetail) {
                qdgroup = Maps.newHashMap();
                qdgroup.put("qacode", outStorageDetail.getQaCode());
                qdgroup.put("deliverno", getSessionUser().getUsername());
                //new String必须加
                batch.put(new String("batch"), qdgroup);

                qacodeBuilder.append(outStorageDetail.getQaCode()).append(",");
                batchnoBuffer.append(outStorageDetail.getBatchNo()).append(",");
            }
        }

        boolean issuccess;
        String returnData;
        try {
            //调出库接口
            Map<String,Object> xmlMap = new HashMap<>(1);
            xmlMap.put("line", new HashMap<String, Object>(5) {{
                put("printcode",printer.getPrinterStr());
                put("type", 2);
                put("outno", outStorage.getShipNo());
                put("outtime", DateUtils.getTime());
                put("userno", getSessionUser().getUsername());
                put("batchs",batch);
            }});
            //当即调用接口
            Map<String,Object> returnMap = wmsService.FEWMS002(xmlMap, qacodeBuilder.toString(), batchnoBuffer.toString());
            returnData = returnMap.get("returnData").toString().replaceAll(" ", "");
            String returnDateTrim = returnData.replace(" ", "");
            issuccess = returnDateTrim.contains("<code>0</code>")||returnDateTrim.contains("\"code\":0")||returnDateTrim.contains("S000A000");
        }catch (Exception e){
            e.printStackTrace();
            resultMap.put("result", false);
            resultMap.put("msg", "系统错误，请联系管理员查看！");
            return resultMap;
        }

        resultMap.put("result", issuccess);
        resultMap.put("msg", issuccess ? "打印成功！" : returnData);
        return resultMap;
    }

}
